﻿using System;
using System.Collections.Generic;
using _5E.Infrastructure.UnitOfWork;
using _5E.NHibernateRepository;
using _5E.NHibernateRepository.Repository;
using NHibernate;
using NHibernate.Criterion;
using WholesaleOnline.Infrastructure.Configuration;
using WholesaleOnline.Model;
using WholesaleOnline.Model.Repository;

namespace WholesaleOnline.Repository
{
    public class BuyerProductRepository : RepositoryBase<WoBuyerProduct, Guid>, IBuyerProductRepository
    {
        public BuyerProductRepository(IUnitOfWork uow) : base(uow) { }

        public IEnumerable<WoProduct> FindProductsFor(Guid buyerId, Guid sellerId, Int32 index, Int32 count, Guid categoryId = new Guid(), string keyword = "")
        {
            IQueryOver<WoBuyerProduct, WoBuyerProduct> buyerProductQueryOver = SessionFactory.CurrentSession.QueryOver<WoBuyerProduct>()
                .Where(b => b.BuyerId == buyerId);

            AppendFindProductsQueryOver(buyerProductQueryOver);

            IQueryOver<WoBuyerProduct, WoProduct> productQueryOver = buyerProductQueryOver.Inner.JoinQueryOver<WoProduct>(b => b.Product)
                .Where(bp => bp.SellerId == sellerId)
                .OrderBy(bp => bp.SortOrder).Asc;

            AppendFindProductsQueryOver(productQueryOver);

            if (!string.IsNullOrEmpty(keyword))
                productQueryOver.Where(bp => bp.Name.IsLike(keyword, MatchMode.Anywhere));

            if (Guid.Empty != categoryId)
                productQueryOver.Inner.JoinQueryOver<WoProductAttribute>(bp => bp.Attributes)
                    .Where(bpa => bpa.AttributeId == categoryId);

            return productQueryOver.Select(b => b.Product)
                .Skip((index - 1) * count).Take(count)
                .List<WoProduct>();
        }

        protected virtual void AppendFindProductsQueryOver(IQueryOver<WoBuyerProduct, WoBuyerProduct> queryOver)
        { }

        protected virtual void AppendFindProductsQueryOver(IQueryOver<WoBuyerProduct, WoProduct> queryOver)
        { }

        public IEnumerable<object[]> FindCategoryIdsFor(Guid buyerId, Guid sellerId, string keyword)
        {
            ICriteria criteria = SessionFactory.CurrentSession.CreateCriteria<WoBuyerProduct>("b");

            AppendCriteria(criteria);

            Conjunction andSubQuery = Expression.Conjunction();
            andSubQuery.Add(Restrictions.Eq("b.BuyerId", buyerId));
            andSubQuery.Add(Restrictions.Eq("bp.SellerId", sellerId));
            andSubQuery.Add(Restrictions.Eq("bpaat.Name", MyApplicationSettingsFactory.ApplicationSettings.CategoryAttributeTypeName));

            if (!string.IsNullOrEmpty(keyword))
                andSubQuery.Add(Restrictions.Like("bp.Name", keyword, MatchMode.Anywhere).IgnoreCase());

            AppendFindCategoryIdsConjunction(andSubQuery);

            IList<object[]> categoryIds = criteria.Add(andSubQuery).AddOrder(new Order("bpaa.SortOrder", true))
                .SetProjection(Projections.ProjectionList()
                    .Add(Projections.Distinct(Projections.Property("bpaa.Id")))
                    .Add(Projections.Property("bpaa.SortOrder"))).List<object[]>();
            return categoryIds;
        }

        protected virtual void AppendFindCategoryIdsConjunction(Conjunction andSubQuery)
        { }

        public override void AppendCriteria(ICriteria criteria)
        {
            criteria.CreateAlias("b.Product", "bp")
                .CreateAlias("bp.Attributes", "bpa")
                .CreateAlias("bpa.Attribute", "bpaa")
                .CreateAlias("bpaa.Type", "bpaat");
        }
    }
}
